package com.dh.core.auth.converter;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4;
import com.dh.core.auth.annotation.jwtAuth;
import com.dh.core.auth.config.JwtProperties;
import com.dh.core.auth.dto.BaseTransferEntity;
import com.dh.core.auth.utils.JwtTokenUtil;
import com.dh.core.auth.utils.MD5Util;
import com.dh.core.common.enums.BizExceptionEnum;
import com.dh.core.common.exception.BussinessException;

/**
 * 
 * @ClassName: WithSignMessageConverter
 * @Description: 带签名的http信息转化器 该转换器配置在FastjsonConfig中
 * @author dinghao
 * @date 2018年11月30日 下午4:21:08
 *
 */
@Component
public class WithSignMessageConverter extends FastJsonHttpMessageConverter4 {

	private Logger log = LoggerFactory.getLogger(this.getClass());

	@Autowired
	JwtProperties jwtProperties;

	@Autowired
	JwtTokenUtil jwtTokenUtil;

	@Override
	public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
			throws IOException, HttpMessageNotReadableException {
		// 获取请求对象
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
				.getRequest();
		// 输入参数流
		InputStream in = inputMessage.getBody();
		// 请求的controller类的方法
		Method[] methods = contextClass.getMethods();
		// 遍历所有的方法
		for (Method method : methods) {
			// 方法上同时有@RequestMapping和@jwtAuth
			if ((method.isAnnotationPresent(RequestMapping.class) || method.isAnnotationPresent(PostMapping.class))
					&& method.isAnnotationPresent(jwtAuth.class)) {
				// 获取方法上的请求路径
				String[] requestPaths = null;
				RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
				if (requestMapping == null) {
					PostMapping postMapping = method.getAnnotation(PostMapping.class);
					requestPaths = postMapping.value();
				} else {
					requestPaths = requestMapping.value();
				}
				// 请求过来的路径
				String requestURI = request.getRequestURI();
				for (String requestPath : requestPaths) {
					/**
					 * 只有加了@jwtAuth请求才能进来
					 */
					// 通过方法上的请求路径和请求过来的路径确定这次请求的方法需要对参数加密
					// 判断该接口传参是否需要校验签名
					if (StringUtils.endsWith(requestURI, requestPath)) {
						Object o = JSON.parseObject(in, super.getFastJsonConfig().getCharset(),
								BaseTransferEntity.class, super.getFastJsonConfig().getFeatures());
						// 先转化成原始的对象
						BaseTransferEntity baseTransferEntity = (BaseTransferEntity) o;
						if (StringUtils.isBlank(baseTransferEntity.getSign())) {
							log.info(
									"标准格式为:{\"sign\":\"a73625693XXXXX43c56763f\",\"object\":{\"password\":\"123456\",\"username\":\"李四\"}}===>[{}]",
									"传参格式异常");
							throw new BussinessException(BizExceptionEnum.PARAMES_ERROR);
						}
						// 校验签名
						String token = request.getHeader(jwtProperties.getHeader()).substring(7);
						String md5KeyFromToken = jwtTokenUtil.getMd5KeyFromToken(token);

						String json = JSON.toJSONString(baseTransferEntity.getObject());
						String encrypt = MD5Util.encrypt(json + md5KeyFromToken);

						if (encrypt.equals(baseTransferEntity.getSign())) {
							log.info("签名校验成功!");
						} else {
							log.info("签名校验失败,数据被改动过!");
							throw new BussinessException(BizExceptionEnum.SIGN_ERROR);
						}
						// 校验签名后再转化成应该的对象
						return JSON.parseObject(json, type);
					}
				}
			}
		}
		// 自己实现,不调用父类
		Object parseObject = null;
		try {
			parseObject = JSON.parseObject(in, super.getFastJsonConfig().getCharset(), type,
					super.getFastJsonConfig().getFeatures());
		} catch (Exception e) {
			throw new BussinessException(BizExceptionEnum.PARAMES_JSON_ERROR);
		}
		
		if (isAllFieldNull(parseObject)) {
			log.info("传参异常");
			throw new BussinessException(BizExceptionEnum.PARAMES_ERROR);
		}
		// return super.read(type, contextClass, inputMessage);
		return parseObject;
	}

	// 判断该对象是否: 返回ture表示所有属性为null 返回false表示不是所有属性都是null
	public static boolean isAllFieldNull(Object obj) {
		boolean flag = true;
		try {
			Class<? extends Object> stuCla = (Class<? extends Object>) obj.getClass();// 得到类对象
			Field[] fs = stuCla.getDeclaredFields();// 得到属性集合
			for (Field f : fs) {// 遍历属性
				f.setAccessible(true); // 设置属性是可以访问的(私有的也可以)
				Object val = f.get(obj);// 得到此属性的值
				if (val != null && f.getName().trim() != "serialVersionUID") {// 只要有1个属性不为空,那么就不是所有的属性值都为空
					flag = false;
					break;
				}
			}
		} catch (Exception e) {
			throw new RuntimeException("WithSignMessageConverter.isAllFieldNull方法获取属性值异常");
		}
		return flag;
	}
}
